package com.comp490.shooter;

import java.util.ArrayList;
import java.util.List;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

import com.comp490.bullet.PlayerBulletPattern;
import com.comp490.input.TouchController;
import com.comp490.level.LevelOne;
import com.comp490.pattern.BulletPattern;
import com.comp490.sprite.BitmapResource;
import com.comp490.sprite.EnemySprite;
import com.comp490.sprite.ShipSprite;

public class GameView extends SurfaceView implements SurfaceHolder.Callback
{
	private List<ShipSprite> ship_sprite;// TODO
	// private PlayerBulletContainer player_bullet_container;
	private PlayerBulletPattern player_bullet_container;
	private List<EnemySprite> enemy_sprite_set;
	private List<BulletPattern> enemy_bullet_patterns;
	private LevelOne levelOne;
	private boolean isSurfaceCreated = false;

	public boolean levelCompleted = false;

	private long scorePool = 0;
	private float scoreLayoutSize = 0;
	char[] scoreText = new char[]{'S','c','o','r','e',':',' ','0','0','0','0','0','0','0','0','0','0'};

	private Bitmap background;
	private int bgFarX;
	private int bgScrollPosition = 0;

	private WorkerBee workerBee;

	private TouchController touchController;

	public GameView(Context context)
	{
		super(context);
		getHolder().addCallback(this);
		workerBee = new WorkerBee(getHolder());
	}

	public GameView(Context context, AttributeSet attrs)
	{
		super(context, attrs);
		getHolder().addCallback(this);
		workerBee = new WorkerBee(getHolder());
	}

	public GameView(Context context, AttributeSet attrs, int defStyle)
	{
		super(context, attrs, defStyle);
		getHolder().addCallback(this);
		workerBee = new WorkerBee(getHolder());
	}

	public void setTouchController(TouchController touchController)
	{
		this.touchController = touchController;
	}

	// If orientation was to changed, or focused away
	public void surfaceChanged(SurfaceHolder holder, int format, int width,
			int height)
	{
		if (workerBee != null && !workerBee.isAlive())
		{
			workerBee.setRunning(true);
			workerBee.start();
		}
	}

	// Called once when gameView is created
	public void surfaceCreated(SurfaceHolder holder)
	{
		if (isSurfaceCreated)
			return;

		Log.v(this.toString(), "GameView Surface being created");
		BitmapResource.loadResources(this);

		resetGame();

		isSurfaceCreated = true;
	}

	public void resetGame()
	{
		levelOne = new LevelOne(this);
		((MainActivity) getContext()).runOnUiThread(new Runnable()
		{
			@Override
			public void run()
			{
				((MainActivity) getContext()).resetLifeUI();
			}
		});// remove specific view
		scorePool = 0;
		for(int i = 1; i < 10; i++)
		{
			scoreText[scoreText.length - i] = '0';
		}
		background = BitmapResource.LEVEL_ONE_BITMAP_BG;
		ship_sprite = new ArrayList<ShipSprite>(1);
		ship_sprite.add(new ShipSprite(this));
		ship_sprite.get(0).reset();
		// player_bullet_container = new PlayerBulletContainer(6, ship_sprite,
		// this);
		player_bullet_container = new PlayerBulletPattern(8, this,
				ship_sprite.get(0));
		if(enemy_sprite_set == null)
			enemy_sprite_set = new ArrayList<EnemySprite>();
		else
			enemy_sprite_set.clear();
		player_bullet_container.setOnScreenEnemies(enemy_sprite_set);
		if(enemy_bullet_patterns == null)
			enemy_bullet_patterns = new ArrayList<BulletPattern>();
		else
			enemy_bullet_patterns.clear();

		scoreLayoutSize = BitmapResource.GAME_SCORE.measureText(scoreText, 0, scoreText.length);
	}

	// Called when program pauses or ends (Ex. back button pressed)
	public void surfaceDestroyed(SurfaceHolder holder)
	{
		pause();
	}

	public void resumeWorkerBee()
	{
		if (workerBee == null)
		{
			workerBee = new WorkerBee(getHolder());
			workerBee.setRunning(true);
			workerBee.start();
		}
	}

	public void pause()
	{
		if (workerBee == null)
			return;

		// done to continuously try and stop thread
		boolean retry = true;
		workerBee.setRunning(false);

		while (retry)
		{
			try
			{
				workerBee.join();
				retry = false;
			}
			catch (InterruptedException e)
			{
				// Keep trying...
			}
		}
		workerBee = null;
	}

	public void updateScore(int points)
	{
		scorePool += points;
	}

	public void updatePhysics()
	{
		updateBackground();
		// Ship Movement
		if (!ship_sprite.get(0).isExploding())
		{
			ship_sprite.get(0).setX(
					ship_sprite.get(0).getX() + touchController.getmPosX());
			ship_sprite.get(0).setY(
					ship_sprite.get(0).getY() + touchController.getmPosY());
		}

		// player ship bullets
		player_bullet_container.updatePosition();

		// enemy ships movement
		for (int i = 0; i < enemy_sprite_set.size(); i++)
		{

			if (enemy_sprite_set.get(i).isActive())
			{
				enemy_sprite_set.get(i).updatePosition();
				enemy_sprite_set.get(i).collisionCheck(ship_sprite.get(0));
			}
		}

		// enemy ship bullets
		for (int i = 0; i < enemy_bullet_patterns.size(); i++)
		{
			if(enemy_bullet_patterns.get(i).isActive())
				enemy_bullet_patterns.get(i).moveAndCheckCollision(ship_sprite);
			else
				enemy_bullet_patterns.remove(i--);
		}

		// level time increment
		if (ship_sprite.get(0).isActive())
			levelCompleted = levelOne.timeInc();

		if (levelCompleted && ship_sprite.get(0).isActive())
			ship_sprite.get(0).setActive(false);
	}
	long scoreTemp;
	@Override
	public void draw(Canvas canvas)
	{
		if (levelCompleted)
		{
			((MainActivity) getContext()).showScoreMenu(levelCompleted);
		}
		drawBackground(canvas);

		for (int i = 0; i < enemy_sprite_set.size(); i++)
			enemy_sprite_set.get(i).draw(canvas);

		for (int i = 0; i < enemy_bullet_patterns.size(); i++)
			enemy_bullet_patterns.get(i).draw(canvas);

		ship_sprite.get(0).draw(canvas);

		player_bullet_container.draw(canvas);

		scoreTemp = scorePool;
		
		for(int i = 1; i < 10; i++)
		{
			scoreText[scoreText.length - i] = (char)('0' + scoreTemp % 10);
			scoreTemp /=10;
		}
		canvas.drawText(scoreText, 0, scoreText.length, getWidth() -scoreLayoutSize, 24, BitmapResource.GAME_SCORE);
	}

	private void updateBackground()
	{
		bgScrollPosition -= 6;
		bgFarX = background.getWidth() + bgScrollPosition;
		if (bgFarX <= 0)
			bgScrollPosition = 0;
	}

	private void drawBackground(Canvas canvas)
	{
		canvas.drawBitmap(background, bgScrollPosition, 0, null);
		canvas.drawBitmap(background, bgFarX, 0, null);
	}

	public List<BulletPattern> getEnemy_bullet_patterns()
	{
		return enemy_bullet_patterns;
	}

	public List<EnemySprite> getEnemy_sprite_set()
	{
		return enemy_sprite_set;
	}

	public long getScore()
	{
		return scorePool;
	}

	private class WorkerBee extends Thread
	{
		private SurfaceHolder surfaceHoler;
		private Thread renderingThread;
		private boolean readyUpdatePhysics = false;
		private boolean running = false;

		public WorkerBee(SurfaceHolder surfaceHolder)
		{
			surfaceHoler = surfaceHolder;
		}

		public void setRunning(boolean run)
		{
			running = run;
		}

		@Override
		public void run()
		{
			Canvas c;
			// PHYSICS RENDER
			if (renderingThread == null)
			{
				renderingThread = new Thread(new Runnable()
				{

					@Override
					public void run()
					{
						while (running)
						{
							if (readyUpdatePhysics)
							{
								synchronized (GameView.this)
								{
									updatePhysics();
									readyUpdatePhysics = false;
								}
							}
						}
					}
				});
				renderingThread.start();
			}
			// RENDERING
			while (running)
			{
				c = null;
				try
				{
					c = surfaceHoler.lockCanvas(null);
					synchronized (surfaceHoler)
					{

						synchronized (GameView.this)
						{
							draw(c);
							readyUpdatePhysics = true;
						}
					}
				}
				catch (Exception e)
				{
					e.printStackTrace();
				}
				finally
				{
					// do this in a finally so that if an exception is thrown
					// during the above, we don't leave the Surface in an
					// inconsistent state
					if (c != null)
						surfaceHoler.unlockCanvasAndPost(c);
				}
			}

			// done to continuously try and stop thread
			boolean retry = true;

			while (retry)
			{
				try
				{
					renderingThread.join();
					retry = false;
				}
				catch (InterruptedException e)
				{
					// Keep trying...
				}
			}
			renderingThread = null;
		}
	}
}
